# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: db\data\users.py
__author__ = "sanyi"
import time, datetime, logging
from sqlalchemy import or_ as sql_or
from sqlalchemy import and_ as sql_and
from sqlalchemy import select as sql_select
from sqlalchemy import func as sql_func
from db import Connection
from dateutil.tz import tzlocal
from db.tables.user2shard import User2ShardRow
from db.tables.users import UserRow, UsersTable, UserConfirmation
from db.tables.licenses import LicenseRow, LicensesTable, LicenseStatus
from server.http_responses.http_errors import Forbidden
from helpers.setup_types import *
from settings_provider import settings

is_sharding_enabled = settings.get("sharding", False)
user_email_2_shard = dict()
user_id_2_shard = dict()
system_users = ("986ad8c0-a5b3-df4d-7028-d5f3c06e936c",)
_logger = logging.getLogger("db.data.users")


def is_master_user(user):
    return user["owner_id"] is None


def get_owner_id(user):
    if user["owner_id"] is None:
        return user["user_id"]
    else:
        return user["owner_id"]


def require_master_user(user):
    if user["owner_id"] is not None:
        raise Forbidden()


def require_system_user(user):
    if user["user_id"] not in system_users:
        raise Forbidden()


def is_system_user(user):
    return user["user_id"] in system_users


def require_at_least_tech_admin(user):
    if user["owner_id"] is None:
        return
    if user["role"] in ("master", "tech_admin"):
        return
    raise Forbidden()


def is_at_least_tech_admin(user):
    if user["owner_id"] is None:
        return True
    elif user["role"] in ("master", "tech_admin"):
        return True
    else:
        return False


def require_at_least_tech_admin_with_access_all(user):
    require_at_least_tech_admin(user)
    if user["role"] == "tech_admin":
        if not user["access_all_groups"]:
            raise Forbidden()


def require_at_least_tester(user):
    if user["owner_id"] is None:
        return
    if user["role"] in ("master", "tech_admin", "tester"):
        return
    raise Forbidden()


def get_user_shard(user_id=None, email=None):
    if not user_id is not None:
        if not email is not None:
            raise AssertionError
    if not is_sharding_enabled:
        return "master"
    else:
        if user_id is not None:
            pass
        try:
            user_shard_info, fetched_at = user_email_2_shard[email]
            if time.time() - fetched_at < 3600:
                return user_shard_info["shard"]
        except KeyError:
            pass

        with Connection("master") as (connection):
            user_shard_info = connection.execute(
                sql_select([User2ShardRow]).where(User2ShardRow.email)
            ).fetchone()
            if not user_shard_info:
                return
            user_shard_info = dict(user_shard_info)
        user_email_2_shard[email] = (user_shard_info, time.time())
        shard_name = user_email_2_shard["shard"]
        return shard_name


owner_table = UsersTable.alias("owner_table")


def update_license(license_key, shard_name, blocking_timeout=None):
    rq_redis_conn = settings.get("rq_redis_conn")
    if blocking_timeout is None:
        timeout = 150
    else:
        timeout = blocking_timeout
    if rq_redis_conn:
        from rq import Queue
        from helpers.licensing.update import job_update_license

        q = Queue(name="license", connection=rq_redis_conn)
        _logger.debug("enqueuing license key update: %s", license_key)
        job = q.enqueue(
            job_update_license,
            shard=shard_name,
            erp_url=settings.get("erp_url", "https://erp.acunetix.com/"),
            license_key=license_key,
            result_ttl=30,
            timeout=timeout,
        )
        if not blocking_timeout:
            return
        start_time = time.time()
        job_id = job.id
        time.sleep(0.5)
        while time.time() < start_time + blocking_timeout:
            job = q.fetch_job(job_id)
            if not job:
                raise Exception("license check job not found")
            if job.status == "finished":
                _logger.debug("license key update success: %s", license_key)
                return job.return_value
            if job.status == "failed":
                _logger.error("license key update failed: %s", license_key)
                raise Exception("license check job failed")
            time.sleep(1)
            _logger.debug("retry license key update: %s", license_key)

        raise Exception("license check job timeout")


def prepare_user_data_ext(
    shard, user_id, refresh_license_time_delta=datetime.timedelta(hours=24)
):
    """
    Assumes master account and setup_type AWS
    :param shard: 
    :param user_id: 
    
    :param refresh_license_time_delta: 
    :return: 
    """
    with Connection(shard) as (db):
        user = prepare_user_data(db, user_id=user_id)
        if not user:
            return
        if user["license_type"] != "customer":
            return user
        last_refresh = user["license_data"]["last_refresh"]
        if last_refresh:
            if (
                datetime.datetime.now(tzlocal()) - last_refresh
                < refresh_license_time_delta
            ):
                return user
    update_license(
        license_key=user["license_key"], shard_name=shard, blocking_timeout=30
    )
    with Connection(shard) as (db):
        return prepare_user_data(db, user_id=user_id)


def prepare_user_data(db_connection, email=None, user_id=None):
    if user_id is not None:
        condition = UserRow.user_id == user_id
    else:
        if email is not None:
            condition = UserRow.email == email.lower()
        else:
            raise ValueError("email or user_id required")
        if is_setup_type(AWS):
            from_clause = UsersTable
            from_clause = from_clause.outerjoin(
                owner_table, owner_table.c.user_id == UsersTable.c.owner_id
            )
            from_clause = from_clause.outerjoin(
                LicensesTable,
                sql_or(
                    sql_and(
                        LicenseRow.license_key == UserRow.license_key,
                        UserRow.owner_id.is_(None),
                    ),
                    sql_and(
                        LicenseRow.license_key == owner_table.c.license_key,
                        UserRow.owner_id.isnot(None),
                    ),
                ),
            )
            query = (
                sql_select(
                    (
                        UserRow,
                        (sql_func.current_timestamp() - UserRow.created).label("old"),
                        (sql_func.current_timestamp() - owner_table.c.created).label(
                            "ow_old"
                        ),
                        owner_table.c.license_type.label("ow_lt"),
                        owner_table.c.created.label("ow_cr"),
                        owner_table.c.api_key_enabled.label("ow_ake"),
                        owner_table.c.confirmation.label("ow_conf"),
                        owner_table.c.extra.label("ow_extra"),
                        LicenseRow.last_refresh.label("l_lrf"),
                        LicenseRow.product_code.label("l_pc"),
                        LicenseRow.status.label("l_status"),
                        LicenseRow.expires.label("l_expires"),
                        LicenseRow.validity_start.label("l_validity_start"),
                        LicenseRow.licenses.label("l_licenses"),
                        LicenseRow.first_activated.label("l_fa"),
                    )
                )
                .select_from(from_clause)
                .where(condition)
                .where(
                    sql_and(
                        UserRow.deleted_at.is_(None), owner_table.c.deleted_at.is_(None)
                    )
                )
                .where(UserRow.enabled.is_(True))
                .where(
                    sql_or(owner_table.c.enabled.is_(True), UserRow.owner_id.is_(None))
                )
            )
        else:
            if is_setup_type(ON_PREMISE_MASTER):
                from_clause = UsersTable
                from_clause = from_clause.outerjoin(
                    owner_table, owner_table.c.user_id == UsersTable.c.owner_id
                )
                query = (
                    sql_select((UserRow,))
                    .select_from(from_clause)
                    .where(condition)
                    .where(UserRow.deleted_at.is_(None))
                    .where(UserRow.enabled.is_(True))
                    .where(
                        sql_or(
                            owner_table.c.enabled.is_(True), UserRow.owner_id.is_(None)
                        )
                    )
                )
            else:
                raise Exception("unsupported setup type")
            user = db_connection.execute(query).fetchone()
            if user is None:
                return
            user = dict(user)
            if user["owner_id"] is None:
                user["master_account"] = True
                user["child_account"] = False
            else:
                user["master_account"] = False
                user["child_account"] = True
        if is_setup_type_aws():
            if user["owner_id"]:
                license_type = user["ow_lt"]
                created = user["ow_cr"]
                user["api_key_enabled"] = user["ow_ake"]
                user["confirmation"] = user["ow_conf"]
                user["old"] = user["ow_old"]
                user["extra"] = user["ow_extra"]
            else:
                license_type = user["license_type"]
                created = user["created"]
            license_data = dict()
            if license_type == "trial":
                if (
                    datetime.timedelta(days=settings.get("ovs_trial_expiry_days", 15))
                ) > user["old"]:
                    license_data["product_code"] = "OVSTRIAL"
                    license_data["expires"] = created + (datetime.timedelta(days=15))
                    license_data["expired"] = False
                    license_data["maintenance_expires"] = license_data["expires"]
                    license_data["maintenance_expired"] = False
                    license_data["activated"] = True
                else:
                    if (
                        datetime.timedelta(
                            days=settings.get("ovs_free_mode_expiry_days", 365)
                        )
                    ) > user["old"]:
                        license_data["product_code"] = "OVS_FREE_MODE"
                        license_data["expires"] = created + (
                            datetime.timedelta(days=365)
                        )
                        license_data["expired"] = False
                        license_data["maintenance_expires"] = license_data["expires"]
                        license_data["maintenance_expired"] = False
                        license_data["activated"] = True
                    else:
                        license_data["product_code"] = "OVS_EXPIRED"
                        license_data["expired"] = True
                        license_data["maintenance_expired"] = True
                    license_data["last_refresh"] = None
            else:
                if license_type == "customer":
                    license_data["license_key"] = user["license_key"]
                    license_data["product_code"] = user["l_pc"]
                    license_data["expires"] = user["l_expires"]
                    license_data["expired"] = LicenseStatus.EXPIRED == user["l_status"]
                    license_data["maintenance_expires"] = license_data["expires"]
                    license_data["maintenance_expired"] = license_data["expired"]
                    license_data["activated"] = user["l_fa"] is not None
                    license_data["first_activated"] = user["l_fa"]
                    license_data["validity_start"] = user["l_validity_start"]
                    license_data["licenses"] = user["l_licenses"]
                    license_data["status"] = user["l_status"]
                    license_data["last_refresh"] = user["l_lrf"]
                    if user["l_status"] in (
                        LicenseStatus.NOT_FOUND,
                        LicenseStatus.UNAUTHORIZED,
                    ):
                        user["enabled"] = False
                    else:
                        return
                    user["license_data"] = license_data
                else:
                    if is_setup_type_on_premise_master():
                        user = dict(user)
                        user["api_key_enabled"] = True
                        user["confirmation"] = UserConfirmation.AUTO_VALIDATED
                        user["api_key_enabled"] = True
                        user["license_data"] = None
                        user["system_user"] = user["user_id"] in system_users
                return user
